package security;

import java.io.*;
import java.security.Key;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.PasswordFinder;
import org.bouncycastle.util.encoders.Hex;
import security.exception.KeyLoadingFailedException;
import server.ServerMain;

/**
 * Helper class to load private and public Keys
 *
 * @author Group 95
 */
public class KeyLoader {

    private static final Logger logger = Logger.getLogger("KeyLoader");
    private static final String STR_KEY_DIR = "keys/";
    private static final String STR_FILE_EXT_PRIV = ".pem";
    private static final String STR_FILE_EXT_PUB = ".pub.pem";
    private static final String STR_FILE_EXT_KEY = ".key";

    {
        logger.setLevel(Level.ALL);
    }

    public static PrivateKey loadPrivateKey(String username) throws KeyLoadingFailedException{
        PEMReader pem = null;
        try {
            StringBuilder strB = new StringBuilder(STR_KEY_DIR).append(username).append(STR_FILE_EXT_PRIV);
            String path = strB.toString();
            Security.addProvider(new BouncyCastleProvider());
            logger.log(Level.INFO, "loadPrivateKey loading from {0} ", new Object[]{path});
            pem = new PEMReader(new FileReader(path), new PasswordFinder() {
      @Override
      public char[] getPassword() {
          System.out.println("Enter pass phrase:");
          try {
              return new BufferedReader(new InputStreamReader(System.in)).readLine().toCharArray();
          } catch (IOException ex) {
              Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
          }
          return null;
      }
  });       KeyPair keyPair = (KeyPair) pem.readObject();
            return keyPair.getPrivate();
        } catch (FileNotFoundException ex) {
            logger.log(Level.SEVERE, null, ex);
            throw new KeyLoadingFailedException(username+"'s Private-KeyFile couldn't be found.");
        } catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
            throw new KeyLoadingFailedException("IOException occured while trying to read "+username+"'s Private-KeyFile.");
        } finally {
            try {
                pem.close();
            } catch (IOException ex) {
                logger.log(Level.SEVERE, null, ex);
                throw new KeyLoadingFailedException("IOException occured while trying to close "+username+"'s Private-KeyFile.");
            }
        }
    }

    public static PublicKey loadPublicKey(String username) throws KeyLoadingFailedException{
        PEMReader pem = null;
        try {
            StringBuilder strB = new StringBuilder(STR_KEY_DIR).append(username).append(STR_FILE_EXT_PUB);
            String path = strB.toString();
            Security.addProvider(new BouncyCastleProvider());
            logger.log(Level.INFO, "loadPublicKey loading from {0} ", new Object[]{path});
            pem = new PEMReader(new FileReader(path));
            //KeyPair keyPair=(KeyPair)pem.readObject();
            //return keyPair.getPublic();
            PublicKey publicKey = (PublicKey) pem.readObject();
            return publicKey;
        } catch (FileNotFoundException ex) {
            logger.log(Level.SEVERE, null, ex);
            throw new KeyLoadingFailedException(username+"'s Public-KeyFile couldn't be found.");
        }
        catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
            throw new KeyLoadingFailedException("IOException occured while trying to read "+username+"'s Public-KeyFile.");
        }
        finally {
            try {
                pem.close();
            } catch (IOException ex) {
                logger.log(Level.SEVERE, null, ex);
                throw new KeyLoadingFailedException("IOException occured while trying to close "+username+"'s Public-KeyFile.");
            }
        }
    }

    /**
     * Load the user-specific secret-key for HMAC message intgrity check.
     * @param username
     * @return
     * @throws FileNotFoundException
     * @throws IOException 
     */
    public static Key loadHMACKey(String username) throws KeyLoadingFailedException {
        FileInputStream fis = null;
        try {
            Security.addProvider(new BouncyCastleProvider());
            byte[] keyBytes = new byte[1024];
            StringBuilder strB = new StringBuilder(STR_KEY_DIR).append(username).append(STR_FILE_EXT_KEY);
            String path = strB.toString();
            logger.log(Level.INFO, "loadHMACKey loading from {0} ", new Object[]{path});
            fis = new FileInputStream(path);
            fis.read(keyBytes);
            fis.close();
            byte[] input = Hex.decode(keyBytes);
            Key key = new SecretKeySpec(input,"HmacSHA256");
            return key;
        } catch (FileNotFoundException ex) {
            logger.log(Level.SEVERE, null, ex);
            throw new KeyLoadingFailedException(username+"'s HMAC-KeyFile couldn't be found.");
        } 
         catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
            throw new KeyLoadingFailedException("IOException occured while trying to read "+username+"'s HMAC-KeyFile.");
        }finally {
            try {
                fis.close();
            } catch (IOException ex) {
                logger.log(Level.SEVERE, null, ex);
                throw new KeyLoadingFailedException("IOException occured while trying to close "+username+"'s HMAC-KeyFile.");
            }
        }
    }
    
    
 
    
}
